

let id = ref 0


let clear () = 
  GlClear.clear  [`color; `depth]



let ouverture (x,y) =
  let _ = Glut.init Sys.argv in
  Glut.initWindowSize x y;
  Glut.createWindow "3D"

let fermeture i =
  Glut.destroyWindow i


(*
  draw_tri ((x1,y1,z1),(x2,y2,z2),(x3,y3,z3))
  prend en arg un triplet de triplet de float et affiche le triangle dont les trois sommets sont nos second triplet
*)
let draw_tri ((x1,y1,z1),(x2,y2,z2),(x3,y3,z3)) =
  GlDraw.begins `triangles; (* `triangles affiche les surfaces
			       pleines; `line_strip affiche en
			       grillage *)
    GlDraw.vertex3 (x1,y1,z1);
    GlDraw.vertex3 (x2,y2,z2);
    GlDraw.vertex3 (x3,y3,z3);
    GlDraw.ends()


(*
  draw_list_tri l
  prend en parametre une liste de triplet de triplet de float et affiche chacun des arguments cf. draw_tri
*)
let rec draw_list_tri = function
  |[] -> ()
  |e::l -> let _ = draw_tri e in draw_list_tri l

  




(* Partie camera
****************************************************)

(* Variable de position de la camera *)
let campos_x = ref 0.
let campos_y = ref 0.
let campos_z = ref (-10.)

(*Variable du point ou la camera regarde *)
let lokpos_x = ref 0.
let lokpos_y = ref 0.
let lokpos_z = ref 0.

(* Variable de l'angle du haut *)
let updir_x = ref 0. 
let updir_y = ref 1.
let updir_z = ref 0.

(* Variable du vecteur directionnel *)
let vectdir_x = ref 0.
let vectdir_y = ref 0.
let vectdir_z = ref 1.
let phi = ref (3.14159265 /. 2.)
let theta = ref (-3.14159265 /. 2.)





(* Passage des coord polaires au coord vect avec une distance de 1*)
let vect3_of_pol (t,p) = 
    (sin(p)*.cos(t),cos(p),(-1.)*.sin(p)*.sin(t))


(* Update des variables de position *)
let updtpos () =
  let (x,y,z) = vect3_of_pol (!theta, !phi) in
  vectdir_x := x;
  vectdir_y := y;
  vectdir_z := z;
  lokpos_x := !campos_x +. !vectdir_x;
  lokpos_y := !campos_y +. !vectdir_y;
  lokpos_z := !campos_z +. !vectdir_z

let adddir () =
  campos_x := !campos_x +. (0.1 *. !vectdir_x);
  campos_y := !campos_y +. (0.1 *. !vectdir_y);
  campos_z := !campos_z +. (0.1 *. !vectdir_z)


let sousdir () =
  campos_x := !campos_x -. (0.1 *. !vectdir_x);
  campos_y := !campos_y -. (0.1 *. !vectdir_y);
  campos_z := !campos_z -. (0.1 *. !vectdir_z)


(* Fonction de test : marche 
affiche les coord du vecteur direction *)
let aff () =
    print_endline ((string_of_float(!vectdir_x)) ^ " " ^ (string_of_float(!vectdir_y)) ^ " " ^ (string_of_float(!vectdir_z)))


(* Fonction de test : marche 
affiche les coord du vecteur position *)
let affichposi () =
    print_endline ((string_of_float(!lokpos_x)) ^ " " ^ (string_of_float(!lokpos_y)) ^ " " ^ (string_of_float(!lokpos_z)))

let affichpos () =
    aff();
    affichposi()

(* Declaration de la camera *)
let cam () =
  updtpos();
  GluMat.look_at ~eye:(!campos_x,!campos_y,!campos_z) ~center:(!lokpos_x,!lokpos_y,!lokpos_z) ~up:(!updir_x,!updir_y,!updir_z)









(* Gestion du clavier
 *********************************************)

let clav () =
  Glut.keyboardFunc ~cb:(fun ~key ~x ~y -> match key with
			     (* Gestion de mes touches de
				base avec un matching *)
			   |13|32|27 -> fermeture !id
			   |54 -> theta := !theta +. 0.1
			   |52 -> theta := !theta -. 0.1
			   |56 -> phi := !phi -. 0.1
			   |50 -> phi := !phi +. 0.1
			   |_ -> print_endline ("merci d'utiliser les chiffres ou les fleches"));
  Glut.specialFunc ~cb:(fun ~key ~x ~y -> match Glut.string_of_special(key) with
			  (* Gestion de l'avance et du recul *)
			  |"KEY_UP" -> adddir ();
			  |"KEY_DOWN" -> sousdir ();
			  (* Gestion du vecteur directionnel *) 
			  |"KEY_RIGHT" -> ()
			  |"KEY_LEFT" -> ()
			  |_ -> ()

)












(* Fonction d'affichage *)
let affich () =
  clear();
  GlMat.mode `projection;
  GlMat.load_identity ();
  GluMat.perspective ~fovy:45. ~aspect:(1.) ~z:(0.1,1000.);
  cam();
  GlMat.mode `modelview;
  GlMat.load_identity ()


(* Fonction de dessin *)
let draw () =
  clear();
  GlMat.mode `modelview;
  GlMat.load_identity ();
  draw_tri ((0.0,1.0,0.0),(-1.0,-1.0,0.0),(1.0,-1.0,0.0));
  Gl.flush ();
  Gl.disable `depth_test;
  Glut.swapBuffers ();
  affich() (* On rappelle la fonction d'affichage pour mettre a jour la position de la camera *) 


(* fonction d'affichage rappele a chaque tour de boucle de mainLoop *)
let reshape ~w ~h =
  affich()

(* fonction de dessin rappele a chaque tour de boucle par mainLoop *)
let display () = 
    draw()









let main () =
  id := ouverture (800,800);
  GlDraw.color (255.,255.,255.);
  clear();

  GlMat.mode `projection;
  GlMat.load_identity ();
  GlDraw.cull_face `both;
  affich();
  draw();


  Glut.reshapeFunc ~cb:reshape;(*appel de ma fonction d'affichage*)
  Glut.displayFunc ~cb:display;
  Glut.idleFunc ~cb:(Some Glut.postRedisplay);
  clav();

  Glut.mainLoop()


let _ =
  main ()
